<?php

namespace control;
/*
*BOM类
*/

use JetBrains\PhpStorm\NoReturn;

class bomClass extends adIndexClass
{
    private const page    = 'bom';
    private const table   = 'bom';
    private const tableMx = 'bom_detail';
    private const title   = '物料清单';
    private array $useOption = ['生产', '委外', '组装拆解', '虚拟'];//BOM用途
    public array $pickOption = ['领料', '配料'];//领料方式

    /**
     * 字段初始化
     */
    public function fieldInit($fun): array
    {
        switch ($fun) {
            default:
                $tr = [
                    'bomVersion'  => [
                        'name'  => "{l.bom.bomList.bomVersion}",
                        'width' => 100,
                        'sort'  => 1,
                    ],
                    'description' => [
                        'name'  => "{l.bom.bomList.description}",
                        'width' => 150,
                    ],
                    'bomType'     => [
                        'name'  => "{l.bom.bomList.bomType}",
                        'width' => 150,
                    ],
                    'typeName'    => [
                        'name'  => '{l.bom.bomList.type}',
                        'width' => 120,
                    ],
                    'code'        => [
                        'name'  => '{l.bom.bomList.code}',
                        'width' => 150,
                        'sort'  => 1,
                    ],
                    'name'        => [
                        'name'  => '{l.bom.bomList.materialName}',
                        'width' => 150,
                    ],
                    'model'       => [
                        'name'  => '{l.bom.bomList.materialModel}',
                        'width' => 150,
                    ],
                    'isDefault'   => [
                        'name'  => '{l.bom.bomList.isDefault}',
                        'width' => 80,
                    ],
                    'state'       => [
                        'name'  => '{l.bom.bomList.state}',
                        'width' => 100,
                    ],
                    'time'        => [
                        'name'  => '{l.bom.bomList.time}',
                        'width' => 150,
                        'sort'  => 1,
                    ]
                ];
        }
        return $tr;
    }

    /*列表页-查询条件*/
    public function bomListOptions($isAsync = true)
    {
        //生成查询表单
        $html = $this->tableShow([
            [
                [
                    L('bom.bomList.bomVersion')   => text(array("name" => "bomVersion")) .
                        hidden(array("name" => "targetId", "value" => $this->get('id'))),
                    L('bom.bomList.code')         => text(array("name" => "code")),
                    L('bom.bomList.materialName') => text(array("name" => "materialName")),
                ],
                [
                    L('bom.bomList.materialModel') => text(array("name" => "materialModel")),
                    L('bom.bomList.time')          => text(array("name" => "time", 'laydate' => ['type' => 'date', 'range' => '~'])),
                    L('bom.bomList.bomType')       => select(["name" => "bomType", 'option' => $this->useOption]),
                ],
                [
                    L('bom.bomList.isDefault') => select(array("name" => "isDefault", "option" => ['是', '否'])),
                    L('bom.bomList.state')     => select(["name" => "state", 'option' => ['启用', '停用']]),
                ]
            ]
        ], 1);
        //返回
        if (!$isAsync) {
            return $html;
        } else {
            return json_encode(['html' => $html], 320);
        }
    }

    /**
     * 物料-bom表
     *
     * @return bool|string
     */
    public function bomList(): bool|string
    {
        $html   = $this->bomListOptions(false);
        $button = "";
        //返回
        $json['html'] = $this->search($html, layout: 'pop', toolButton: $button);
        return json_encode($json, 320);
    }

    public function bomListSearch(): bool|string
    {
        $materialId = $this->post('targetId');
        //like查询数组
        $like = array(
            "bomVersion" => $this->post('bomVersion'),//证件编号
            "b.name"     => $this->post('materialName'),
            "model"      => $this->post('materialModel'),
            "code"       => $this->post('code'),
            "bomType"    => $this->post('bomType'),
        );
        //全等查询数组
        $equal = array(
            "a.state"      => $this->post('state'),
            "a.materialId" => $materialId,// 父件
            "a.coid"       => self::$coid
        );
        $and   = '';
        if ($this->post('time')) {
            $timeArr = explode(' ~ ', $this->post('time'));
            $and     .= " and date(a.time) >='{$timeArr[0]}' and date(a.time) <='{$timeArr[1]}'";
        }
        if ($this->post('isDefault')) {
            $isDefault = $this->post('isDefault') == '是' ? 1 : 0;
            $and       .= " and a.isDefault = $isDefault";
        }
        //排序
        $orderBy = $this->listSort(array(
            "search" => $this->post('list_sort_key') ?: 'time',
            "sort"   => $this->post('list_sort') ?: "desc",
            "array"  => array(),
        ));
        //获取查询结果
        $where                       = search(array("like" => $like, "=" => $equal)) . $and;
        $page                        = $this->page(array(
            "table" => self::table . " as a join material as b on a.materialId = b.id",
            'field' => "a.*,b.name,b.model,b.code,b.typeId,b.typeName",
            "where" => $where,
            "order" => $orderBy['orderBy']
        ));
        $_SESSION[self::page]['sql'] = $page['fullSql'];
        //获取自定义字段参数
        $installSearch = $this->installSearch();
        $body          = [];
        //表格控件区
        $liButton = array("");
        //获取记录
        $url = root . "control/adIndex.html?cla=" . self::page;
        foreach ($page['array'] as $array) {
            //列表控件
            $dominate   = array(
                "edit"   => array("title" => lang('bom.bomList.edit'), "click" => "newIframe('" . lang('bom.bomList.detail') . "','" . $url . "&fun=edit&id=" . $array['id'] . "')"),
                "detail" => array("title" => lang('bom.bomList.detail'), "click" => "newIframe('" . lang('bom.bomList.detail') . "','" . $url . "&fun=detail&id=" . $array['id'] . "')"),
                'browse' => array('title' => lang('bom.bomList.preview'), 'click' => "window.open('" . root . "control/adIndex.html?cla={$this->get('cla')}&fun=preView&id={$array['id']}')"),
                'track'  => array("title" => lang('bom.bomList.preview'), "click" => "newIframe('" . lang('bom.bomList.bomForm') . "','" . root . "control/adIndex.html?cla=orderTrack&fun=bomPreview&id=" . $array['id'] . "')"),
            );
            $liButton[] = $this->dominate($dominate);
            //本行初始化
            $row = [];
            foreach ($installSearch['key'] as $key) {
                switch ($key) {
                    case 'isDefault':
                        $row[] = $array['isDefault'] ? '是' : '否';
                        break;
                    default:
                        $row[] = isset($array[$key]) && $array[$key] ? $array[$key] : '';
                }
            }
            $body[] = $row;
        }
        //生成页面
        $li = $this->li(array(
            "body"        => $body,
            "install"     => $installSearch,
            "button"      => array("html" => $liButton),
            "orderBySign" => $orderBy,
            "page"        => $page['para'],
        ));
        //返回
        $json['html'] = $page['hint'] . "<form name='bomListForm'>" . $li . "</form>" . $page['button'] . clear;
        return json_encode($json, 320);
    }

    public static function getDepartmentAllMaterial($data = []): string
    {
        // 条件
        $data['where'] = $data['where'] ?? "pid='0' and coid = '" . self::$coid . "'";
        // 点击事件
        $data['click'] = $data['click'] ?? "replaceDetail(this,'" . self::page . "')";
        //当前层级
        $data['level'] = isset($data['level']) ? $data['level'] + 1 : 0;
        // 结果
        $result = find(['table' => 'material_type', 'field' => 'id,name', 'where' => $data['where'] . " and coid = '" . self::$coid . "' order by list asc,time asc"]);
        $style  = ($data['where'] == "pid='0'" || $data['level'] == 0) ? '' : " class='child-node' data-level='{$data['level']}' ";
        $temp   = "<ul {$style} {$data['where']}>";
        $textcontent_ico = "<span class='textcontent_ico'></span>";
        if ($result['array']) {
            foreach ($result['array'] as $value) {
                // 角标
                $arrow = "<span class='arrow'  onclick=\"liZoom($(this).parent())\"></span>";
                // 判断下级是否存在
                $data['where'] = " pid='{$value['id']}' and coid = '" . self::$coid . "' ";
                $has           = query('material_type', $data['where']);
                if ($has['id']) {
                    $temp .= "<li class='arrow-li' data-id='{$value['id']}' onclick=\"{$data['click']}\">
                                {$arrow}
                                <span class='textcontent'>{$textcontent_ico}{$value['name']}</span>
                            </li>";
                    $temp .= self::getDepartmentAllMaterial($data);
                } else {
                    $temp .= "<li class='arrow-no-li'  data-id='{$value['id']}' onclick=\"{$data['click']}\">
                                <span class='textcontent'>{$textcontent_ico}{$value['name']}</span>
                            </li>";
                }
            }
        }
        $temp .= '</ul>';
        return $temp;
    }

    /**
     * 异步加载
     *
     */
    public function homeRightJson(): bool|string
    {
        $json['html'] = $this->homeRight();
        return json_encode($json, 320);
    }

    public function homeRightJsonSearch(): bool|string
    {
        return $this->homeSearch();
    }

    /**
     * 左侧搜索框
     *
     * @return string
     */
    public function getContainerLeftJson(): string
    {
        $option['click'] = 'replaceContent(this, \'bom\')';
        $json['html']    = self::getDepartmentAllMaterial($option);
        return json_encode($json, 320);
    }


    public function homeHtml(): string
    {
        //返回
        $rightHtml       = $this->homeRight();
        $option['click'] = 'replaceContent(this, \'bom\')';
        $all             = self::getDepartmentAllMaterial($option);
        //物料清单分类数展示
        if (optionSettingClass::getSettingItem('公共', 'showBomCatalog')) {
            return componentClass::leftNav([
                'searchvalue'=>isset($_SESSION[self::page]['keyword']) ? $_SESSION[self::page]['keyword'] : '',
                'title'=>lang('bom.homeHtml.search'),
                'inputOther'=>" onblur=\"typeSession(this,'material','" . self::page . "')\" ",
                'all'=>$all,
                'rightHtml'=>$rightHtml,
            ]);
        } else {
            return $rightHtml;
        }
    }

    /*列表页-查询条件*/
    public function home()
    {
        //返回
        return $this->homeFun($this->homeHtml());
    }

    public function catalog(): bool|string
    {
        //数据查询
        $info = query(self::table . '_type', " id = '" . $this->post('id') . "' ");
        $pid  = $info['pid'] ?: ($this->post('pid') ?: '0');
        //表单
        $html = $this->layerEdit([
            "table" => [
                [
                    must . lang('material.catalog.type') . "：" => text(["name" => "name", "value" => $info['name'] ?? null, 'class' => 'text']),
                ],
                [
                    lang('material.catalog.list') . "：" => text(["name" => "list", "value" => $info['list'] ?? null, 'class' => 'text']) .
                        hidden(['name' => 'pid', 'value' => $pid]),
                ]
            ]
        ]);
        //返回
        return $this->layer(["title" => lang('material.catalog.edit'), "height" => 220, "html" => $html]);
    }

    public function catalogEdit(): bool|string
    {
        //赋值
        $field = [
            'pid'  => $this->post('pid') ?: '0',
            "name" => $this->post('name'),      //部门名称
            "list" => $this->post('list'),      //排序号
        ];
        $info  = query(self::table . '_type', " id = '" . $this->post('id') . "' ");
        //判断
        if (!$this->power(self::page, "edit")) {
            $json['warn'] = lang('material.catalogEdit.power');
        } elseif (empty($field['name'])) {
            $json['warn'] = lang('material.catalogEdit.name');
        } elseif (sqlNum(self::table . '_type', "pid = '$field[pid]' and coid ='" . self::$coid . "' and name = '$field[name]' and id != '" . $this->post('id') . "' ") > 0) {
            $json['warn'] = lang('material.catalogEdit.repeat');
        } elseif (empty($this->post('id'))) {
            $json['warn'] = lang('material.catalogEdit.idEmpty');
        } elseif (empty($info['id'])) {
            $field        = array_merge($field, ["id" => $this->post('id'), 'coid' => self::$coid, "time" => $this->time]);
            $json['warn'] = insert(["table" => self::table . '_type', "field" => $field]);
        } else {
            $json['warn'] = update(["table" => self::table . '_type', "field" => $field, "where" => "id = '" . $this->post('id') . "'"]);
        }
        if (in_array($json['warn'], array("新增成功", "更新成功"))) {
            //添加日志
            $type = mb_substr($json['warn'], 0, 2, 'utf-8');
            $text = str_replace(['{{staffName}}', '{{type}}', '{{name}}'], [$this->control['name'], $type, $field['name']], lang('material.catalogEdit.log'));
            $this->logText(array("type" => self::page, "text" => $text));
            //提示
            $_SESSION['warn'] = $json['warn'];
            $json['warn']     = 2;
        }
        //返回
        return json_encode($json, 320);
    }

    /*列表页-查询条件*/
    public function homeOptions($isAsync = true)
    {
        $typeId = $this->post('objId') ?? null;
        //生成查询表单
        $html = $this->tableShow([
            [
                [
                    L('bom.bomList.bomVersion')   => text(array("name" => "bomVersion")) .
                        hidden(array('name' => 'typeId', 'value' => $typeId)),
                    L('bom.bomList.code')         => text(array("name" => "code")),
                    L('bom.bomList.materialName') => text(array("name" => "materialName")),
                ],
                [
                    L('bom.bomList.materialModel') => text(array("name" => "materialModel")),
                    L('bom.bomList.time')          => text(array("name" => "time", 'laydate' => ['type' => 'date', 'range' => '~'])),
                    L('bom.bomList.bomType')       => select(["name" => "bomType", 'option' => $this->useOption]),
                ],
                [
                    L('bom.bomList.isDefault') => select(array("name" => "isDefault", "option" => ['是', '否'])),
                    L('bom.bomList.state')     => select(["name" => "state", 'option' => ['启用', '停用']]),
                ]
            ]
        ], 1);
        //返回
        if (!$isAsync) {
            return $html;
        } else {
            return json_encode(['html' => $html], 320);
        }
    }

    public function homeRight()
    {
        $html = $this->homeOptions(false);
        //控件
        $button = "";
        $url    = root . "control/adIndex.html?cla=" . self::page;
        if ($this->power(self::page, "edit")) {
            $button .= "<span onclick=\"newIframe('" . lang('bom.bomList.detail') . "','" . $url . "&fun=edit')\" class='spanButton'>" . lang('bom.bomList.new') . "</span>\n";
        }
        if ($this->power(self::page, "del")) {
            $button .= "<span class='spanButton' onclick=\"layer('{$this->get('cla')}', 'operate', {'act': 'del'})\">" . lang('bom.bomList.del') . "</span>\n";
        }
        //导入
        if ($this->power(self::page, 'import')) {
            $button .= "<span class='spanButton' onclick=\"layer('importTemplate','importFrame',{cla:'" . self::page . "'})\">导入</span>";
        }
        if ($this->power(self::page, "export")) {
            $button .= "<span class='spanButton' onclick=\"layer('importTemplate','exportFrame',{cla:'" . self::page . "'})\">导出</span>";
        }
        if ($this->power(self::page, "edit")) {
            $button .= "<span onclick=\"layer('{$this->get('cla')}','stateSwitch',{type:'启用'})\" class='spanButton'>" . lang('bom.bomList.start') . "</span>\n";
            $button .= "<span onclick=\"layer('{$this->get('cla')}','stateSwitch',{type:'停用'})\" class='spanButton'>" . lang('bom.bomList.stop') . "</span>\n";
        }
        //返回
        return $this->search($html, layout: 'pop', toolButton: $button);
    }

    /*客户列表-查询结果*/
    public function homeSearch()
    {
        //like查询数组
        $like = array(
            "bomVersion" => $this->post('bomVersion'),//证件编号
            "b.name"     => $this->post('materialName'),
            "model"      => $this->post('materialModel'),
            "code"       => $this->post('code'),
            "bomType"    => $this->post('bomType'),
            "b.typePath" => $this->post('typeId'),
        );
        //全等查询数组
        $equal = array(
            "a.state" => $this->post('state'),
            "a.coid"  => self::$coid
        );
        $and   = '';
        if ($this->post('time')) {
            $timeArr = explode(' ~ ', $this->post('time'));
            $and     .= " and date(a.time) >='{$timeArr[0]}' and date(a.time) <='{$timeArr[1]}'";
        }
        if ($this->post('isDefault')) {
            $isDefault = $this->post('isDefault') == '是' ? 1 : 0;
            $and       .= " and a.isDefault = $isDefault";
        }
        //排序
        $orderBy = $this->listSort(array(
            "search" => $this->post('list_sort_key') ?: 'time',
            "sort"   => $this->post('list_sort') ?: "desc",
            "array"  => array(),
        ));
        //获取查询结果
        $where                       = search(array("like" => $like, "=" => $equal)) . $and;
        $page                        = $this->page(array(
            "table" => self::table . " as a join material as b on a.materialId = b.id",
            'field' => "a.*,b.name,b.model,b.code,b.typeId,b.typeName",
            "where" => $where,
            "order" => $orderBy['orderBy']
        ));
        $_SESSION[self::page]['sql'] = $page['fullSql'];
        //获取自定义字段参数
        $installSearch = $this->installSearch();
        $body          = [];
        //表格控件区
        $liButton = array(
            $this->checkAll("listForm", "listId")
        );
        //获取记录
        $url = root . "control/adIndex.html?cla=" . self::page;
        foreach ($page['array'] as $array) {
            //列表控件
            $dominate   = array(
                "box"    => array("name" => "listId", "value" => $array['id']),
                "edit"   => array("title" => lang('bom.bomList.edit'), "click" => "newIframe('" . lang('bom.bomList.detail') . "','" . $url . "&fun=edit&id=" . $array['id'] . "')"),
                "detail" => array("title" => lang('bom.bomList.detail'), "click" => "newIframe('" . lang('bom.bomList.detail') . "','" . $url . "&fun=detail&id=" . $array['id'] . "')"),
                'browse' => array('title' => lang('bom.bomList.preview'), 'click' => "window.open('" . root . "control/adIndex.html?cla={$this->get('cla')}&fun=preview&id={$array['id']}')"),
                'track'  => array("title" => lang('bom.bomList.preview'), "click" => "newIframe('" . lang('bom.bomList.bomForm') . "','" . root . "control/adIndex.html?cla=orderTrack&fun=bomPreview&id=" . $array['id'] . "')"),
            );
            $liButton[] = $this->dominate($dominate);
            //本行初始化
            $row = [];
            foreach ($installSearch['key'] as $key) {
                switch ($key) {
                    case 'isDefault':
                        $row[] = $array['isDefault'] ? '是' : '否';
                        break;
                    default:
                        $row[] = isset($array[$key]) && $array[$key] ? $array[$key] : '';
                }
            }
            $body[] = $row;
        }
        //控件
        $button = "";
        //生成页面
        $li = $this->li(array(
            "body"        => $body,
            "install"     => $installSearch,
            "button"      => array("html" => $liButton),
            "orderBySign" => $orderBy,
            "page"        => $page['para'],
        ));
        //返回
        $json['html'] = $page['hint'] . $button . "<form name='listForm'>" . $li . "</form>" . $page['button'] . clear;
        return json_encode($json, 320);
    }


    /**
     * 编辑页
     * @return string
     */
    public function edit(): string
    {
        if ($this->get('copyId')) {
            $id = $this->get('copyId');
        } else {
            $id = $this->get('id') ?: suiji();
        }

        $info     = query(self::table, " id = '" . $id . "' ");
        $button[] = [
            'style' => 'li-btn-blue-bg',
            "name"  => lang('bom.edit.save'),
            "type"  => "点击事件",
            "title" => lang('bom.edit.save'),
            'fun'   => "subForm('" . self::page . "EditForm','" . root . "control/adIndex.html?cla=" . self::page . "&fun=editEdit')"
        ];
        $tr[]     = ['', '{l.bom.edit.code}', '{l.bom.edit.name}', '{l.bom.edit.model}', '{l.bom.edit.unti}', '{l.bom.edit.bomVersion}', '{l.bom.edit.supplier}', '{l.bom.edit.num}', '{l.bom.edit.loss}', '{l.bom.edit.source}', '{l.bom.edit.pickType}'];
        $result   = find(array('table' => self::tableMx, 'where' => "orderId = '$info[id]' order by list"));
        foreach ($result['array'] as $k=>$array) {
            if ($this->get('copyId')) {
                $array['id'] = suiji();
            }
            $material = query('material', " id = '$array[materialId]'");
            //把此物料的单位组成单位选项
            $unitOption  = machiningOrderClass::unitOption($material['id']);
            $houseSelect = '';
            if ($array['pickType'] == '配料') {
                $houseSelect = idSelect(array(
                    'name'     => 'warehouseId[' . $array['id'] . ']',
                    'value'    => $array['warehouseId'],
                    'title'    => lang('bom.edit.warehouseId'),
                    'sqlId'    => 'id',
                    'sqlForm'  => "warehouse where state = '启用' and coid = '" . self::$coid . "' order by time asc",
                    'sqlField' => 'name'
                ));
            }
            $tr[] = [
                componentClass::tablePperation($k+1,"delTableRow(this)").
                hidden(array('name' => 'mxId[]', 'value' => $array['id'])) .
                hidden(array('name' => 'materialDetailId[]', 'value' => $array['materialId'])),
                $material['code'],
                $material['name'],
                $material['model'],
                select(array('name' => 'mxUnit[]', 'option' => $unitOption, 'value' => $array['unit'])),
                idSelect(array('name' => 'bomId[]', 'title' => lang('bom.edit.bomVersion'), 'sqlForm' => "bom where materialId = '$array[materialId]' and state = '启用'", 'sqlId' => 'id', 'sqlField' => 'bomVersion', 'value' => $array['bomId'])),
                idSelect(array('name' => 'supplierId[]', 'title' => lang('bom.edit.supplier'), 'sqlForm' => "supplier where coid = '" . self::$coid . "' and state = '启用'", 'sqlId' => 'id', 'sqlField' => 'name', 'value' => $array['supplierId'])),
                text(array('name' => 'mxNum[]', 'other' => self::digitalFiltering('numPrecision'), 'class' => 'text', 'value' => self::lostZero($array['num'], 'numPrecision'))),
                text(array('name' => 'loss[]', 'class' => 'text', 'other' => self::digitalFiltering('lossRate'), 'value' => (float)$array['loss'] * 100)),
                $material['source'],
                radio(array('name' => 'pickType[' . $array['id'] . ']', 'change' => 'changePickType', 'value' => $this->pickOption, 'checked' => $array['pickType'])) . $houseSelect
            ];
        }

        $table          = $this->listTable(array('tr' => $tr, 'end' => true));
        $choiceProduct = lang('bom.edit.choiceProduct');
        $but         = <<<efo
                        <span class="smallButton" onclick="layer('{$this->get('cla')}','addMx',$('form[name=bomEditForm]').serialize())">{$choiceProduct}</span>
efo;
        //表单
        $material       = query('material', " id = '$info[materialId]'");
        $unitOption     = machiningOrderClass::unitOption($material['id']);
        $parentName     = $material['id'] ? ($material['code'] . '-' . $material['name'] . '-' . $material['model']) : '';
        $data['button'] = $this->tableShowButton($button);
        $body = $this->edit4([
            '基本信息' => [
                [
                    must . lang('bom.edit.bomVersion') . "："     => text(["name" => "bomVersion", 'class' => 'text', "value" => $info['bomVersion']]) . componentClass::tipComponent(lang('bom.edit.build')),
                    must . lang('bom.bomList.description') . "：" => text(["name" => "description", 'class' => 'text', "value" => $info['description']]),
                    must . lang('bom.bomList.bomType') . "："     => checkbox(["name" => "bomType", 'value' => $this->useOption, "checked" => $info['bomType'] ? explode(',', $info['bomType']) : [$this->useOption[0]]]),
                ],
                [
                    must . lang('bom.edit.parent') . "：" => "<span style='margin-left: 10px' id='materialName'>" . $parentName . hidden(array('name' => 'materialId', 'value' => $info['materialId'])) . "</span><span class='del-row-button' onclick=\"layer('{$this->get('cla')}','addSingleMx',{})\">" . lang('bom.edit.choice') . "</span>",
                    must . lang('bom.edit.datum') . "：" =>
                        text(["name" => "num", 'other' => self::digitalFiltering('numPrecision'), "value" => self::lostZero($info['num'], 'numPrecision')]) .
                        select(array('name' => 'unit', 'id' => "mainUnit", 'title' => lang('bom.edit.unti'), 'option' => $unitOption, 'value' => $info['unit'])),
                    must . lang('bom.edit.isDefault')   => radio(array('name' => 'isDefault', 'value' => ['1' => '是', '0' => '否'], 'checked' => $info['isDefault'] ?: 0)),
                ],
                [
                    lang('bom.edit.text') . "："         => textarea(["name" => "text", "value" => $info['text']]),
                ],
                [
                    "附件：" => fileUploadClass::addFileComponent($info['id'], 'BOM', self::page, self::page . 'EditForm')
                ],
            ]
        ]);
        $body .= $this->editList([
            'id' => 'materialTable',
            'title' => lang('bom.edit.child'),
            'button' => $but,
            'html' => $table,
        ]);
        $data['html']   = $this->pageEdit([
            "html"  => $body,
            'hidden' => hidden(['name' => 'id', 'value' => $this->get('id')]),
        ]);
        $data['html']   .= <<<efo
        <script>
        function addRow(classify=''){
            if (classify==='single'){
                $.post(root+'control/adIndex.html?cla={$this->get('cla')}&fun=addSingle',$("form[name='mxSingleForm']").serialize(),function(res) {
                    $('#bomAddSingleMx').hide()
                    $("#materialName").html(res.html);
                    $("#mainUnit").empty().append(res.unitOption);
                    resetNumber($("#mainUnit"))
                },'json');
            }else{
                $.post(root+'control/adIndex.html?cla={$this->get('cla')}&fun=addMxEdit',$("form[name='mxForm']").serialize(),function(res) {
                    $('#bomAddMx').hide();
                    $("#materialTable tbody").append(res.html);
                    resetNumber($("#materialTable"))
                },'json');
            }
            
        }
        function changePickType(e){
            let type = e.value;
            if (type==='配料'){
               let id = $(e).parent().parent().parent().find("[name='mxId[]']").val();
               $.post(root+'control/adIndex.html?cla=bom&fun=changePickType',{id:id},function(res) {
                   if (res.warn ==2){
                       $(e).parent().after(res.html)
                   }else{
                       msg(res.warn,'error');
                   }
               },'json')
            }else{
                $(e).parent().parent().find("select").remove();
            }
        }
        </script>
        efo;
        //返回
        return $this->tab($data);
    }

    public function changePickType(): bool|string
    {
        $id = $this->post('id');
        if (empty($id)) {
            $json['warn'] = lang('bom.changePickType.empty');
        } else {
            $json['warn'] = 2;
            $json['html'] = idSelect(array(
                'name'     => 'warehouseId[' . $id . ']',
                'title'    => lang('bom.changePickType.warehouseId'),
                'sqlId'    => 'id',
                'sqlForm'  => "warehouse where state = '启用' and coid = '" . self::$coid . "' order by time asc",
                'sqlField' => 'name'
            ));
        }
        return json_encode($json, 320);
    }

    /**
     * 获取bom版本
     * @param $materialId
     * @return string
     */
    private function getBomVersion($materialId): string
    {
        $num = static::total(array('table' => self::table, 'where' => "materialId = '$materialId' and coid = '" . self::$coid . "'"));
        return 'BOM' . ($num + 1);
    }

    /**
     * 编辑
     * @return bool|string
     * @throws \Exception
     */
    public function editEdit(): bool|string
    {
        $fileIdArr           = $this->post('fileId');
        $id                  = $this->post('id') ?: self::getId();
        $mxIdArr             = $this->post('mxId') ?: [];
        $materialDetailIdArr = $this->post('materialDetailId');
        $numArr              = $this->post('mxNum');
        $unitArr             = $this->post('mxUnit');
        $lossArr             = $this->post('loss');
        $bomArr              = $this->post('bomId');
        $supplierArr         = $this->post('supplierId');
        $warehouseIdArr      = $this->post('warehouseId');
        $pickTypeArr         = $this->post('pickType');

        $field      = [
            'description' => $this->post('description'),
            'text'        => $this->post('text'),
            'isDefault'   => $this->post('isDefault'),
            'num'         => $this->post('num') ? self::formattingFigure($this->post('num'), 'numPrecision') : '',
            'unit'        => $this->post('unit'),
            'materialId'  => $this->post('materialId'),
            'bomType'     => $this->post('bomType') ? implode(',', $this->post('bomType')) : '',
            'bomVersion'  => $this->post('bomVersion'),
        ];
        $annotation = [
            'description' => lang('bom.editEdit.description'),
            'num'         => lang('bom.edit.datum'),
            'materialId'  => lang('bom.editEdit.materialId'),
            'bomType'     => lang('bom.editEdit.bomType'),
            'unit'        => '单位',
        ];
        $rules      = [
            'description' => 'required',
            'num'         => 'required',
            'materialId'  => 'required',
            'bomType'     => 'required',
            'unit'        => 'required',
        ];
        // 校验是否符合规则
        $vt     = new \verify();
        $result = $vt->setAliases($annotation)->validate($field, $rules)->isOk();
        if ($result === false) {
            $json['warn'] = $vt->getErrs()[0];  // 多个规则提示最前面一条
            goto resp;
        }
        $where = " id = '$id' ";
        $info  = query(self::table, $where);
        //判断
        if (!$this->power(self::page, "edit")) {
            $json['warn'] = lang('bom.editEdit.power');
        } elseif (static::is_null_array($mxIdArr)) {
            $json['warn'] = lang('bom.editEdit.child');
        } elseif (static::is_null_array($unitArr)) {
            $json['warn'] = lang('bom.editEdit.unit');
        } elseif (static::is_null_array($numArr)) {
            $json['warn'] = lang('bom.editEdit.num');
        } elseif (static::total(array('table' => self::table, "where" => "id !='$id' and coid = '" . self::$coid . "' and materialId = '$field[materialId]' and bomVersion = '$field[bomVersion]'")) > 0) {
            $json['warn'] = lang('bom.editEdit.repeat');
        } else {
            $json['warn'] = '';
            foreach ($materialDetailIdArr as $k => $detailId) {
                //判断相互的组成关系，防止死循环
                if ($this->isRepeatParent($detailId, $field['materialId'], $bomArr[$k])) {
                    $material     = query('material', "id = '$detailId'");
                    $json['warn'] = str_replace(['{{materialName}}'], [$material['name']], lang('bom.editEdit.relationship'));
                    break;
                }
            }
            if (empty($json['warn'])) {
                $this->startTrans();
                if (static::total(array('table' => self::table, "where" => "materialId = '$field[materialId]' and isDefault = 1")) == 0) {
                    $field['isDefault'] = 1;
                }
                if (!$info['id']) {
                    $userNo              = codeTemplateClass::generateCode(self::page, [
                        'prefix' => 'BOM' . date('Ymd'),
                        'table'  => self::table,
                        'field'  => 'orderNo',
                        'where'  => " and coid = '" . self::$coid . "'",
                    ], $field);
                    $field['bomVersion'] = $field['bomVersion'] ?: $this->getBomVersion($field['materialId']);
                    $field               = array_merge($field, [
                        'id'      => $id,
                        'orderNo' => $userNo,
                        'coid'    => self::$coid,
                        'state'   => '启用',
                        'stid'    => $this->control['stid'],
                    ]);
                    $json['warn']        = static::insert(["table" => self::table, "field" => $field]);
                } else {
                    $json['warn'] = static::update([
                        "table" => self::table,
                        "field" => $field,
                        "where" => $where
                    ]);
                }

                //添加或更新报价单明细
                if (is_array($mxIdArr)) {
                    foreach ($mxIdArr as $k => $mxId) {
                        $bomMx      = query(self::tableMx, "id = '$mxId'");
                        $numArr[$k] = self::formattingFigure($numArr[$k], 'numPrecision');
                        if (!empty($bomMx['id'])) {
                            //更新
                            $warn = static::update([
                                "table" => self::tableMx,
                                "field" => [
                                    'materialId'  => $materialDetailIdArr[$k],
                                    'num'         => $numArr[$k],
                                    'unit'        => $unitArr[$k],
                                    'bomId'       => $bomArr[$k],
                                    'supplierId'  => $supplierArr[$k],
                                    'loss'        => (float)$lossArr[$k] / 100,
                                    'pickType'    => $pickTypeArr[$mxId],
                                    'warehouseId' => $warehouseIdArr[$mxId] ?? '',
                                ],
                                "where" => " id = '$mxId'"
                            ]);
                        } else {
                            //新增
                            $warn = static::insert([
                                "table" => self::tableMx,
                                "field" => [
                                    'id'          => $mxId,
                                    'orderId'     => $id,
                                    'coid'        => self::$coid,
                                    'materialId'  => $materialDetailIdArr[$k],
                                    'num'         => $numArr[$k],
                                    'unit'        => $unitArr[$k],
                                    'bomId'       => $bomArr[$k],
                                    'supplierId'  => $supplierArr[$k],
                                    'loss'        => (float)$lossArr[$k] / 100,
                                    'pickType'    => $pickTypeArr[$mxId],
                                    'warehouseId' => $warehouseIdArr[$mxId] ?? '',
                                ],
                            ]);
                        }
                        if (!in_array($warn, ['新增成功', '更新成功'])) {
                            $json['warn'] = $warn;
                            break;
                        }
                    }
                }

                if (in_array($json['warn'], ["新增成功", "更新成功"])) {
                    $this->commitTrans();
                    if (is_array($fileIdArr)) {
                        update(array('table' => 'file', 'field' => ['targetId' => $id], 'where' => " targetId = '' and id in ('" . implode("','", $fileIdArr) . "')"));
                    }
                    delete(array('table' => self::tableMx, 'where' => " id not in ('" . implode("','", $mxIdArr) . "') and orderId = '$id'"));
                    if ($field['isDefault'] == 1) {
                        update(array('table' => self::table, 'field' => array('isDefault' => 0), 'where' => "materialId = '$field[materialId]' and id !='$id'"));
                    }
                    //添加日志
                    $type = mb_substr($json['warn'], 0, 2, 'utf-8');
                    $text = str_replace(['{{staffName}}', '{{type}}', '{{id}}'], [$this->control['name'], $type, $id], lang('bom.editEdit.log'));
                    $this->logText(["type" => self::page, "text" => $text]);
                    auditClass::operateRecord($id, 'BOM', $type);
                    //返回
                    $_SESSION['warn'] = $json['warn'];
                    $json['warn']     = 2;
                    $json['href']     = root . "control/adIndex.html?cla=" . $this->get('cla') . "&fun=detail&id=" . $id;
                } else {
                    $this->rollback();
                }
            }
        }

        resp:
        return json_encode($json, 320);
    }


    /**
     * 判断子物料是否在父件中存在，防止死循环
     */

    public function isRepeatParent($detailId, $parentId, $bomId)
    {
        $material = query('material', "id = '$detailId'", "id");
        if ($material['id'] == $parentId) {
            return true;
        }
        if ($bomId) {
            $bomAll = find(['table' => 'bom_detail', "where" => "orderId = '$bomId' order by list"]);
            foreach ($bomAll['array'] as $array) {
                $bool = $this->isRepeatParent($array['materialId'], $parentId, $array['bomId']);
                if ($bool) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 父件选择
     * @return bool|string
     */
    public function addSingle(): bool|string
    {
        $material           = query('material', "id = '" . $this->post('mxId') . "'");
        $unitOption         = machiningOrderClass::unitOption($material['id']);
        $json['unitOption'] = option(array("title" => lang('bom.edit.unti'), "option" => $unitOption, "value" => $material['unit']));
        $json['html']       = materialClass::getName($material['id']) . hidden(array('name' => 'materialId', 'value' => $material['id']));
        return json_encode($json, 320);
    }

    /**
     *
     * @return bool|string
     */
    public function addMx()
    {
        $html   =
            materialClass::typeSelect(name: 'type') .
            text(array("name" => "code", "title" => lang('bom.addMx.code'))) .
            text(array("name" => "materialName", "title" => lang('bom.addMx.materialName'))) .
            text(array("name" => "model", "title" => lang('bom.addMx.model'))) .
            hidden(array('name' => 'classify', 'value' => $this->post('classify'))) .
            hidden(array('name' => 'materialPid', 'value' => $this->post('materialId'))) .
            hidden(array('name' => 'materialDetailId', 'value' => $this->post('materialDetailId') ? implode(',', $this->post('materialDetailId')) : ''));
        $button = "<input style='margin-left: 5px' onclick=\"addRow('" . $this->post('classify') . "')\" type='button' class='searchSub' value='" . lang('bom.addMx.sub') . "'>";
        $html   = $this->search($html);
        return $this->layer(array("title" => lang('bom.addMx.add'), "height" => 600, "width" => 1000, "html" => $html, "button" => $button));
    }

    /**
     *添加产品
     */
    public function addMxSearch(): bool|string
    {
        $classify   = $this->post('classify');
        $materialId = $this->post('materialDetailId') ? explode(',', $this->post('materialDetailId')) : [];
        $where      = " 1=1 and a.id not in ('" . implode("','", $materialId) . "')";
        if ($classify != 'single') {
            $where .= " and a.id !='" . $this->post('materialPid') . "' ";
        }
        $and = '';
        if ($this->post('type')) {
            $allTypeId = materialClass::getAllChildTypeId($this->post('type'));
            $and       .= " and a.typeId in ('" . implode("','", $allTypeId) . "')";
        }
        $like     = [
            'a.name'  => $this->post('materialName'),
            'a.code'  => $this->post('code'),
            'a.model' => $this->post('model'),
        ];
        $equal    = [
            'a.state' => '启用',
            'a.coid'  => self::$coid,
        ];
        $where    .= search(["like" => $like, "=" => $equal]) . $and;
        $page     = $this->page([
            "table"   => "material as a",
            'field'   => "a.*",
            "where"   => $where,
            'pageNum' => 50,
            "order"   => "a.`time` ASC",
        ]);
        $formName = $classify == 'single' ? 'mxSingleForm' : 'mxForm';
        //获取表头
        $checkAll = $classify == 'single' ? '' : $this->checkAll($formName, "mxId");
        $tr[]     = [$checkAll, '{l.bom.addMxSearch.type}', '{l.bom.addMxSearch.code}', '{l.bom.addMxSearch.name}', '{l.bom.addMxSearch.model}'];
        //获取记录
        foreach ($page['array'] as $array) {
            $dominate = array(
                "box" => array("name" => "mxId", "value" => $array['id']),
            );
            if ($classify == 'single') {
                //单选
                $choose = "<input type='radio' name='mxId' value='$array[id]'>";
            } else {
                $choose = $this->dominate($dominate);
            }
            $tr[] = array(
                $choose,
                $array['typeName'],
                $array['code'],
                $array['name'],
                $array['model'],
            );
        }
        $json['html'] = $page['hint'] . "<form name='$formName'>" . hidden(array('name' => 'materialPid', 'value' => $this->post('materialPid'))) . $this->tableMany(array("tr" => $tr)) . "</form>" . $page['button'];
        return json_encode($json, 320);
    }


    /**
     *添加父件
     * @return bool|string
     */
    public function addSingleMx()
    {
        $html   =
            materialClass::typeSelect(name: 'type') .
            text(array("name" => "code", "title" => lang('bom.addSingleMx.code'))) .
            text(array("name" => "materialName", "title" => lang('bom.addSingleMx.materialName'))) .
            text(array("name" => "model", "title" => lang('bom.addSingleMx.model'))) .
            hidden(array('name' => 'classify', 'value' => $this->post('classify')));
        $button = "<input style='margin-left: 5px' onclick=\"addRow('single')\" type='button' class='searchSub' value='" . lang('bom.addSingleMx.sub') . "'>";
        $html   = $this->search($html);
        return $this->layer(array("title" => lang('bom.addSingleMx.add'), "height" => 600, "width" => 1000, "html" => $html, "button" => $button));
    }

    /**
     *添加父件
     */
    public function addSingleMxSearch(): bool|string
    {
        $and   = " and source in ('自制','委外','虚拟')";
        $like  = [
            'name'     => $this->post('materialName'),
            'code'     => $this->post('code'),
            'model'    => $this->post('model'),
            'typePath' => $this->post('type'),
        ];
        $equal = [
            'state' => '启用',
            'coid'  => self::$coid,
        ];
        $where = search(["like" => $like, "=" => $equal]) . $and;
        $page  = $this->page([
            "table"   => "material",
            "where"   => $where,
            'pageNum' => 50,
            "order"   => "`time` ASC",
        ]);
        //获取表头
        $tr[] = ['', '{l.bom.addSingleMx.typeId}', '{l.bom.addSingleMx.code}', '{l.bom.addSingleMx.materialName}', '{l.bom.addSingleMx.model}'];
        //获取记录
        foreach ($page['array'] as $array) {
            //单选
            $choose = "<input type='radio' name='mxId' value='$array[id]'>";
            $tr[]   = array(
                $choose,
                $array['typeName'],
                $array['code'],
                $array['name'],
                $array['model'],
            );
        }
        $json['html'] = $page['hint'] . "<form name='mxSingleForm'>" . $this->tableMany(array("tr" => $tr)) . "</form>" . $page['button'];
        return json_encode($json, 320);
    }

    /**
     * 编辑
     *
     * @return bool|string
     */
    public function addMxEdit(): bool|string
    {
        $mxIdArr     = $this->post('mxId');
        $materialPid = $this->post('materialPid');//父件ID
        if (!$this->power(self::page, 'edit')) {
            $json['warn'] = lang('bom.addMxEdit.power');
        } elseif (empty($mxIdArr) || !is_array($mxIdArr)) {
            $json['warn'] = lang('bom.addMxEdit.choice');
        } else {
            $tr = [];
            foreach ($mxIdArr as $materialId) {
                if ($materialId == $materialPid) {
                    //禁止和父件相互嵌套造成死循环
                    continue;
                }
                $material       = query('material', "id = '$materialId'");
                $id             = self::getId();
                $unitOption     = machiningOrderClass::unitOption($material['id']);
                $selectUnit     = select(array('name' => 'mxUnit[]', 'title' => lang('bom.addMxEdit.unit'), 'value' => $material['unit'], 'option' => $unitOption));
                $bomSelect      = idSelect(array('name' => 'bomId[]', 'title' => lang('bom.addMxEdit.bomVersion'), 'sqlForm' => "bom where materialId = '$material[id]' and state = '启用'", 'sqlId' => 'id', 'sqlField' => 'bomVersion'));
                $supplier       = idSelect(array('name' => 'supplierId[]', 'title' => lang('bom.edit.supplier'), 'sqlForm' => "supplier where coid = '" . self::$coid . "' and state = '启用'", 'sqlId' => 'id', 'sqlField' => 'name'));
                $pickTypeSelect = radio(array('name' => 'pickType[' . $id . ']', 'change' => 'changePickType', 'value' => $this->pickOption, 'checked' => $this->pickOption[0]));
                $tr[]              = [
                    componentClass::tablePperation('',"delTableRow(this)").
                    hidden(array('name' => 'mxId[]', 'value' => $id)) .
                    hidden(array('name' => 'materialDetailId[]', 'value' => $materialId)),
                    $material['code'],
                    $material['name'],
                    $material['model'],
                    $selectUnit,
                    $bomSelect,
                    $supplier,
                    text(array('name' => 'mxNum[]', 'type' => 'text', 'class' => 'text', 'other' => self::digitalFiltering('numPrecision'), 'value' => '')),
                    text(array('name' => 'loss[]', 'type' => 'text', 'class' => 'text', 'other' => self::digitalFiltering('lossRate'), 'value' => '')),
                    $material['source'],
                    $pickTypeSelect,
                ];
            }
            $json['html'] = $this->tableMany(array('tr' => $tr, 'thead' => false));
            $json['warn'] = 2;
        }
        return json_encode($json, 320);
    }


    /*详情页*/
    public function detail(): string
    {
        $info = query(self::table, " id = '{$this->get('id')}'");
        if (empty($info['id'])) {
            $html = lang('bom.detail.notFind');
        } else {
            //菜单
            $data   = array(
                "id" => $info['id'],
            );
            $button = [];
            if ($this->power(self::page, "edit")) {
                //按钮
                $button[] = [
                    "name"  => lang('bom.detail.edit'),
                    "type"  => "顶部页卡",
                    "title" => lang('bom.detail.editBom'),
                    "url"   => $this->root . "control/adIndex.html?cla={$this->get('cla')}&fun=edit&id=" . $info['id'],
                    'style' => 'li-btn-blue-bg',
                ];
                //按钮
                $button[] = [
                    "name"  => lang('bom.detail.copy'),
                    "type"  => "顶部页卡",
                    "title" => lang('bom.detail.editBom'),
                    "url"   => $this->root . "control/adIndex.html?cla={$this->get('cla')}&fun=edit&copyId=" . $info['id'],
                ];

                $button[] = [
                    "name"  => lang('bom.detail.preview'),
                    "type"  => "点击事件",
                    "title" => lang('bom.detail.preview'),
                    'fun'   => "window.open('" . root . "control/adIndex.html?cla={$this->get('cla')}&fun=preview&id={$info['id']}')",
                ];

                $state    = $info['state'] == '停用' ? '启用' : '停用';
                $button[] = [
                    "name"  => $state,
                    "type"  => "点击事件",
                    'title' => lang('bom.detail.stateSwitch'),
                    "fun"   => "layer('" . $this->get('cla') . "','stateSwitch',{id:'" . $info['id'] . "',type:'{$state}'})",
                ];

            }
            if ($this->power(self::page, "del")) {
                //按钮
                $button[] = [
                    "name" => lang('bom.detail.del'),
                    "type" => "弹出层",
                    "cla"  => $this->get('cla'),
                    "fun"  => "operate",
                    "post" => ["act" => 'del', "id" => $info['id']],
                ];
            }
            //操作记录
            $button[] = self::operateLogBut($info['id']);

            $tr[]   = ['{l.bom.detail.code}', '{l.bom.detail.name}', '{l.bom.detail.model}', '{l.bom.detail.bomVersion}', '{l.bom.edit.supplier}', '{l.bom.detail.unit}', '{l.bom.detail.num}', '{l.bom.detail.loss}', '{l.bom.detail.source}', '{l.bom.detail.pickType}'];
            $result = find(array('table' => self::tableMx, 'where' => "orderId = '$info[id]' order by list"));
            foreach ($result['array'] as $array) {
                $material  = query('material', " id = '$array[materialId]'");
                $bom       = query('bom', "id = '$array[bomId]'");
                $warehouse = query('warehouse', "id = '$array[warehouseId]'");
                $supplier  = query('supplier', "id = '$array[supplierId]'");
                $tr[]      = [
                    $material['code'],
                    $material['name'],
                    $material['model'],
                    $bom['bomVersion'],
                    $supplier['name'],
                    $array['unit'],
                    self::lostZero($array['num'], 'numPrecision'),
                    ($array['loss'] * 100) . '%',
                    $material['source'],
                    $array['pickType'] == '配料' ? ($array['pickType'] . '-' . $warehouse['name']) : $array['pickType'],
                ];
            }
            $material = query('material', " id = '$info[materialId]'");
            //生成表单
            $data['button'] = $this->tableShowButton($button);
            $data['html']   = $this->tableShow(array(
                "基本信息" => array(
                    array(
                        lang('bom.detail.bomVersion')  => $info['bomVersion'],
                        lang('bom.detail.description') => $info['description'],
                        lang('bom.detail.bomType')     => $info['bomType'],
                    ),
                    array(
                        lang('bom.detail.isDefault') => $info['isDefault'] ? '是' : '否',
                        lang('bom.detail.datum') => self::lostZero($info['num'], 'numPrecision'),
                        lang('bom.detail.parent')    => $material['code'] . '-' . '-' . $material['name'] . '-' . $material['model'],
                    ),
                    array(
                        lang('bom.detail.orderNo') => $info['orderNo'],
                        lang('bom.detail.stid')    => self::findStaff($info['stid']),
                        lang('bom.detail.state')   => $info['state']
                    ),
                    array(
                        lang('bom.detail.text')  => pre($info['text']),
                    ),

                ),
                "附件"                     => array(
                    array(
                        fileUploadClass::showFile($info['id'], 'BOM')
                    ),
                ),
            ));
            $data['html'] .= $this->detailList([
                'title' => lang('bom.detail.child'),
                'html' => $this->listTable(['tr' => $tr, 'showSort' => true]),
            ]);
            //生成页面
            $html = $this->tab($data);
        }
        //返回
        return $html;
    }

    /**
     * 启用/停用
     */
    public function stateSwitch(): bool|string
    {
        $type = $this->post('type');
        //生成表单
        $html = $this->layerEdit(array("table" => array(
            array(
                lang('material.stateSwitch.tips') => lang('material.stateSwitch.modify') . $type,
            ),
        ), 'hidden'                            => hidden(array('name' => 'type', 'value' => $type))));
        //返回
        return $this->layer(array("title" => lang('material.stateSwitch.switching'), "height" => 165, "html" => $html, 'formTwo' => 'listForm'));
    }

    /**
     * 启用/停用
     */
    public function stateSwitchEdit(): bool|string
    {
        $idArr = $this->post('id') ? [$this->post('id')] : $this->post('listId');
        $state = $this->post('type');
        if (!$this->power(self::page, "edit")) {
            $json['warn'] = lang('bom.editEdit.power');
        } elseif (empty($idArr) || !is_array($idArr)) {
            $json['warn'] = lang('material.stateSwitchEdit.choice');
        } elseif (!in_array($state, ['启用', '停用'])) {
            $json['warn'] = lang('material.stateSwitchEdit.typeError');
        } else {
            $field        = [
                'state' => $state,
            ];
            $json['warn'] = update(array('table' => self::table, 'field' => $field, 'where' => " id in ('" . implode("','", $idArr) . "')"));
            if (in_array($json['warn'], ["新增成功", "更新成功"])) {
                foreach ($idArr as $id) {
                    auditingFollow(array(
                        "type"   => "bom",
                        "typeId" => $id,
                        "text"   => "【{$this->control['name']}】" . $state,
                    ));
                }
                //添加日志
                $type = mb_substr($json['warn'], 0, 2, 'utf-8');
                $text = str_replace(['{{staffName}}', '{{type}}', '{{state}}', '{{ids}}'], [$this->control['name'], $type, $state, implode(",", $idArr)], lang('material.stateSwitchEdit.log'));
                $this->logText(["type" => self::page, "text" => $text]);
                //返回
                $_SESSION['warn'] = $json['warn'];
                $json['warn']     = 2;
            }
        }
        //返回
        return json_encode($json, 320);
    }


    public static function getDepartmentAll($data = []): string
    {
        // 条件
        $data['where'] = $data['where'] ?? "orderId='{$data['id']}'";
        // 结果
        $result = find(['table' => self::tableMx, 'where' => $data['where'] . " order by list asc"]);
        $style  = ' class="child-node"';
        $temp   = "<ul {$style} pid='{$data['id']}'>";
        // 角标
        $arrow   = arrow;
        $lastone = lastone;
        if ($result['array']) {
            foreach ($result['array'] as $value) {
                // 判断下级是否存在
                $data['where'] = " orderId='{$value['bomId']}' ";
                $material      = query('material', "id = '$value[materialId]'");
                $num           = self::lostZero($value['num'], 'numPrecision');
                if ($value['bomId']) {
                    $temp .= "<li class='arrow-li' onclick=\"switch_li(this)\" data-id='{$value['id']}'>{$arrow}{$material['name']}（{$num}{$value['unit']}）</li>";
                    $temp .= self::getDepartmentAll($data);
                } else {
                    $temp .= "<li class='arrow-no-li' onclick=\"switch_li(this)\"  data-id='{$value['id']}'>{$lastone}{$material['name']}（{$num}{$value['unit']}）</li>";
                }
            }
        }
        $temp .= '</ul>';
        return $temp;
    }

    /**
     * 预览BOM
     */
    public function preView(): string
    {
        $bom           = query(self::table, " id = '{$this->get('id')}'");
        $material      = query('material', "id = '$bom[materialId]'");
        $company       = query('company', "coid = '" . self::$coid . "'");
        $data['where'] = "orderId='{$bom['id']}'";
        $data['id']    = $bom['id'];
        $all           = self::getDepartmentAll($data);
        $arrow         = arrow;
        $bomText       = lang('bom.preView.bom');
        $bomNum        = self::lostZero($bom['num'], 'numPrecision');
        $html          = <<<efo
                            <div class="paper">
                            <div class="paper-title-block">
                            <span class="paper-title-text">{$company['name']}</span>
                             <div class="sub-title">{$material['name']}{$bomText}</div>
                            </div>
                            
                            <div class="container-left paper-content-block" id="container-left">
                                <ul class="child-node" pid="0">
                                <li class='arrow-li' onclick="switch_li(this)" data-id='{$bom['id']}'>{$arrow}{$material['name']}（{$bomNum}{$bom['unit']}）</li>
                                     {$all}
                                </ul>
                            </div>
                            </div>

efo;


        return $this->header() . $this->style() . $html . warn() . $this->footer();
    }

    /**
     * 头部
     * @return string
     */
    public function header(): string
    {
        $root  = root;
        $title = para('title');//网站标题
        return <<<eof
                <html lang="zh">
                <head>
                <title>{$title}</title>
                    <meta charset="UTF-8">
                    <link rel="stylesheet" type="text/css" href="{$root}static/stylesheet/css.css?v=4.2.710">
                    <link rel="icon" type="image/x-icon" href="{$root}favicon.ico?v=4.2.710">
                    <script type="text/javascript" src="{$root}static/javascript/jquery-1.11.2.min.js"></script>
                    <script type="text/javascript" src="{$root}static/javascript/js.js"></script>
                    <script type="text/javascript" src="{$root}static/javascript/lib.js"></script>
                </head>
                <body>
               
eof;
    }

    /**
     * 打印样式
     * @return string
     */
    public function style(): string
    {
        return <<<eof
        <style>
         body{background-color: #AAAAAA;}
        .paper{width: 210mm;height: 100%;background-color: #fff; margin: 0 auto;overflow: auto;padding: 20px}
        .paper-title-block{background-color: #fff;text-align: center;width: 210mm;}
        .paper-title-text,.sub-title{font-size: 16px;font-weight: bold;padding: 5px}
        .paper-content-block{padding: 10px 20px;}
        .container-left{width: 100%;height: auto;background-color: white;min-height: unset;min-width: unset}
   
        </style>\n
eof;
    }

    /**
     *尾部
     * @return string
     */
    public function footer(): string
    {
        return <<<eof
<script>
function switch_li(obj){
     let id = $(obj).attr('data-id')
      ulScal(obj, id)
      $(obj).addClass('active')
}
</script>
            </body>
            </html>
eof;
    }

    // 操作中转
    public function operate()
    {
        $act  = $this->post('act') ?? '';
        $pwd  = $word = false; // 需要密码
        $form = $power = '';
        switch ($act) {
            default:
                $act      = 'del';
                $msg      = lang('bom.operate.msg');
                $title    = self::page . 'Delete';
                $function = 'delete';
                $form     = self::page . 'OperateForm, listForm, quoForm';
                $power    = '';
                break;
        }
        if (!$this->power(self::page, $act)) {
            $_SESSION['warn'] = str_replace(['{{msg}}'], [$msg], lang('bom.operate.warn'));
            $json             = [
                'warn' => 2,
                'href' => root . 'control/adIndex.html?cla=' . $this->get('cla') . '&fun=home',
            ];
        } else {
            return $this->confirm([
                'title'    => $title,
                'function' => $function,
                'form'     => $form,
                'power'    => $power,
                'pwd'      => $pwd,
                'word'     => $word
            ]);
        }

        resp:
        return json_encode($json, 320);
    }

    /**
     * 删除
     * @return bool|string
     */
    public function delete()
    {
        $array = $this->post('listId') ?? $this->post('id');
        if (!$this->power(self::page, "del")) {
            $json['warn'] = lang('bom.delete.power');
        } elseif (empty($array)) {
            $json['warn'] = lang('bom.delete.noChoice');
        } else {
            $text  = "";
            $x     = 0;
            $array = is_array($array) ? $array : [$array];
            foreach ($array as $id) {
                $info = query(self::table, " id = '$id' ");
                if ($info['state'] == '启用') {
                    $warn = lang('bom.delete.fail');
                } else {
                    //最后删除基本参数
                    delete(array("table" => self::table, "where" => " id = '$id' "));
                    delete(array("table" => self::tableMx, "where" => " orderId = '$id' "));
                    //返回
                    $warn = lang('bom.delete.success');
                    $x++;
                }
                $text .= str_replace(['{{id}}'], [$id], lang('bom.delete.text')) . $warn . "。<br>";
            }
            //添加日志
            $text = str_replace(['{{staffName}}'], [$this->control['name']], lang('bom.delete.log')) . "<br>" . $text;
            $this->logText(array("type" => self::page, "text" => $text));
            $_SESSION['warn'] = str_replace(['{{x}}'], [$x], lang('bom.delete.warn'));
            $json['warn']     = 2;
            $json['href']     = root . "control/adIndex.html?cla=" . $this->get('cla') . "&fun=home";
        }
        return json_encode($json, 320);
    }


    /**
     * 创建物料
     * @param $materialField
     * @return array|string
     */
    public function createMaterial($materialField): array|string
    {
        $materialObj = new materialClass();
        $resOption   = $materialObj->supplyControlOption($materialField['source']);
        $material    = query('material', "code = '$materialField[code]' and coid = '" . self::$coid . "'");
        if (!empty($material['id'])) {
            //更新来源及供应控制，如此单位不在物料的单位中，则更新为主单位
            $updateField = [
                'source'        => $materialField['source'],
                'supplyControl' => implode(',', array_keys($resOption)),
            ];
            /*if ($materialField['unit'] && !in_array($materialField['unit'], machiningOrderClass::unitOption($material['id']))) {
                $updateField['unit'] = $materialField['unit'];
            }*/
            self::update(array('table' => 'material', 'field' => $updateField, 'where' => "id = '$material[id]'"));
            return $material;
        }
        $materialField['typeId']   = materialClass::createType($materialField['typeId']);
        $typeName                  = materialClass::getTypePath($materialField['typeId']);
        $materialField['typePath'] = materialClass::getTypePath($materialField['typeId'], 'id', '/');
        $materialField['typeName'] = $typeName;
        // 校验是否符合规则
        $vt         = new \verify();
        $annotation = [
            'typeId' => '物料分类',
            'code' => '物料编码',
            'name' => '物料名称',
            'unit' => '主单位',
        ];
        $rules      = [
            'typeId' => 'required',
            'code' => 'required',
            'name' => 'required',
            'unit' => 'required',
        ];
        $result     = $vt->setAliases($annotation)->validate($materialField, $rules)->isOk();
        if ($result === false) {
            return $material;
        }
        $subject                   = '产成品';
        if (str_contains($typeName, '半成品')) {
            $subject = '半成品';
        } elseif (str_contains($typeName, '原材料')) {
            $subject = '原材料';
        }
        $materialField = array_merge($materialField, [
            'id'            => suiji(),
            "coid"          => self::$coid,
            "upStock"       => '-1',
            "downStock"     => '-1',
            "shelf"         => '-1',
            'supplyControl' => implode(',', array_keys($resOption)),
            'length'        => 0,
            'width'         => 0,
            'height'        => 0,
            "subject"       => $subject,
            "costType"      => '移动加权平均',
        ]);
        //生成编码,此处为特殊处理
        if (empty($materialField['code']) || self::total(['table' => 'material', 'where' => "coid = '" . self::$coid . "' and code = '$materialField[code]'"]) > 0) {
            $material_type         = explode('->', $typeName);
            $material_field        = [
                'oneType'   => isset($material_type[0]) ? PYClass::encode($material_type[0], strtoupper: true) : '',
                'twoType'   => isset($material_type[1]) ? PYClass::encode($material_type[1], strtoupper: true) : '',
                'threeType' => isset($material_type[2]) ? PYClass::encode($material_type[2], strtoupper: true) : '',
            ];
            $materialField['code'] = codeTemplateClass::generateCode('material', [
                'prefix' => 'WL' . date('Ymd'),
                'table'  => 'material',
                'field'  => 'code',
                'where'  => " and coid = '" . self::$coid . "' ",
            ], $material_field);
        }
        $warn = self::insert(array('table' => 'material', 'field' => $materialField));
        if ($warn == '新增成功') {
            return query('material', "id = '" . $materialField['id'] . "'");
        }
        return $material;
    }

    /**
     * 下载模板
     */
    public function downloadModel()
    {
        $templateId     = $this->get('templateId');
        if (!$this->power(self::page, 'import')) {
            $_SESSION['warn'] = lang('bom.downloadModel.power');
        } else {
            $staffProfile  = new staffProfilesClass();
            $columns       = $staffProfile->getAllColumns();
            $materialObj   = new materialClass();
            $exampleData[] = ['BOM202112020001', 'v1', '样例数据', '生产', '办公用品->打印机', 'M0002', '打印机', 'model-1', '自制', '台', 1, '否', '测试', '原材料', 'Y01', '颜料', 'model-2', '采购', '瓶', 'v1', 2, 0.1, '领料', '', ''];
            $exampleData[] = ['BOM202112020001', 'v1', '样例数据', '生产', '办公用品->打印机', 'M0002', '打印机', 'model-1', '自制', '台', 1, '否', '测试', '原材料', 'Y02', '挡板', 'model-3', '采购', '张', 'v1', 1, 0, '领料', '', ''];
            $excel         = $this->excelHead();
            $fileName      = self::title . '导入模板-' . importTemplateClass::getName($templateId) . '.xlsx';
            $filePath      = $excel->fileName($fileName, 'sheet1');
            $format        = new \Vtiful\Kernel\Format($filePath->getHandle());
            $validation    = new \Vtiful\Kernel\Validation();
            $templateField = importTemplateClass::templateField(self::page, 'importFieldInit', id:$templateId);
            $index         = 0;
            foreach ($templateField as $k => $array) {
                if ($array['display']) {
                    $backgroundStyle = null;
                    if (importTemplateClass::getIsMustValue($this->importFieldInit(), $array['columnName'])) {
                        //必填项判断
                        $backgroundStyle = $format->background(
                            0xFFC04B
                        )->toResource();
                    }
                    $filePath->insertText(0, $index, $array['aliasName'], '', $backgroundStyle);
                    foreach ($exampleData as $y => $example) {
                        $exampleVal = match ($array['columnName']) {
                            'BOM编号' => $example[0],
                            'BOM版本' => $example[1],
                            'BOM描述' => $example[2],
                            'BOM用途' => $example[3],
                            '父件分类' => $example[4],
                            '父件编码' => $example[5],
                            '父件名称' => $example[6],
                            '规格型号' => $example[7],
                            '来源' => $example[8],
                            '单位' => $example[9],
                            '基准数量' => $example[10],
                            '是否默认' => $example[11],
                            '备注' => $example[12],
                            '子件分类' => $example[13],
                            '子物料编码' => $example[14],
                            '子物料名称' => $example[15],
                            '子物料规格型号' => $example[16],
                            '子物料来源' => $example[17],
                            '子物料单位' => $example[18],
                            '子物料BOM版本' => $example[19],
                            '额定数量' => $example[20],
                            '损耗率' => $example[21],
                            '供料方式' => $example[22],
                            '发料仓编码' => $example[23],
                            '发料仓名称' => $example[24],
                            default => '',
                        };
                        $filePath->insertText($y + 1, $index, $exampleVal);
                        switch ($array['columnName']) {
                            case '来源':
                            case '子物料来源':
                                //下拉列表
                                $validation->validationType(\Vtiful\Kernel\Validation::TYPE_LIST)
                                    ->valueList($materialObj->sourceOption);
                                $filePath = $filePath->validation($columns[$index] . ($y + 2), $validation->toResource());
                                break;
                            case '供料方式':
                                //下拉列表
                                $validation->validationType(\Vtiful\Kernel\Validation::TYPE_LIST)
                                    ->valueList($this->pickOption);
                                $filePath = $filePath->validation($columns[$index] . ($y + 2), $validation->toResource());
                                break;
                            case 'BOM用途':
                                //下拉列表
                                $validation->validationType(\Vtiful\Kernel\Validation::TYPE_LIST)
                                    ->valueList($this->useOption);
                                $filePath = $filePath->validation($columns[$index] . ($y + 2), $validation->toResource());
                                break;
                        }
                    }
                    $index++;
                }
            }
            $text = str_replace(['{{staffName}}'], [$this->control['name']], lang('bom.downloadModel.log'));
            $this->logText(["type" => self::page, "text" => $text]);
            $this->excelOutPut($filePath, $fileName);
            exit(0);
        }
        header("Location:" . getenv("HTTP_REFERER"));
    }

    /**
     * Excel导入
     */
    public function importData()
    {
        $templateId     = $this->post('templateId');
        if (!$this->power(self::page, 'import')) {
            $json['warn'] = lang('bom.importData.power');
        } else {
            $fomatArray = [];//导入数据格式同一为TYPE_STRING
            foreach ($this->importFieldInit() as $value) {
                $fomatArray[] = \Vtiful\Kernel\Excel::TYPE_STRING;
            }
            $data      = $this->importHead(format: $fomatArray);
            $x         = 0;
            $text      = '';
            $headArray = [];
            $row_list  = 0;
            foreach ($data as $i => $row) {
                $row_list++;
                if ($i == 0) {
                    $templateField = importTemplateClass::templateField(self::page, 'importFieldInit', id:$templateId);
                    $headArray = importTemplateClass::combinHead($templateField,$row);
                }
                if ($i > 0) {
                    $rowData = formSubArray($row);
                    //只接收模板中选中的字段的值
                    $cell = [];
                    foreach ($headArray as $index => $headName) {
                        $cell[$headName] = $rowData[$index] ?? '';
                    }
                    //初始化未被模板需要的字段的值
                    foreach ($this->importFieldInit() as $value) {
                        $cell[$value['columnName']] = $cell[$value['columnName']] ?? '';
                    }
                    //父件
                    $materialField = [
                        'typeId' => $cell['父件分类'],
                        'code'   => $cell['父件编码'],
                        'name'   => $cell['父件名称'],
                        'model'  => $cell['规格型号'],
                        'source' => $cell['来源'] ?: '采购',
                        'unit'   => $cell['单位'],
                    ];

                    $material      = $this->createMaterial($materialField);

                    $field = [
                        'description' => $cell['BOM描述'],
                        'bomType'     => $cell['BOM用途'],
                        'text'        => $cell['备注'],
                        'num'         => $cell['基准数量'] ? self::formattingFigure($cell['基准数量'], 'numPrecision') : '',
                        'unit'        => $materialField['unit'] ?: $material['unit'],
                        'materialId'  => $material['id'],
                        'bomVersion'  => $cell['BOM版本'],
                        'isDefault'   => $cell['是否默认'] == '是' ? 1 : 0
                    ];

                    $annotation = [
                        'description' => lang('bom.importData.description'),
                        'num'         => lang('bom.importData.num'),
                        'materialId'  => lang('bom.importData.materialId'),
                        'bomType'     => lang('bom.importData.bomType'),
                        'unit'        => lang('bom.importData.unit'),
                    ];
                    $rules      = [
                        'description' => 'required',
                        'num'         => 'required',
                        'materialId'  => 'required',
                        'bomType'     => 'required',
                        'unit'        => 'required',
                    ];
                    $unitOption = machiningOrderClass::unitOption($material['id']);

                    $warn          = '';
                    $bomTypeOption = explode(',', $field['bomType']);
                    foreach ($bomTypeOption as $val) {
                        if (!in_array($val, $this->useOption)) {
                            $warn = str_replace(['{{i}}'], [$row_list], lang('bom.importData.typeNotIn')) . "<br>";
                            break;
                        }
                    }
                    // 校验是否符合规则
                    $vt     = new \verify();
                    $result = $vt->setAliases($annotation)->validate($field, $rules)->isOk();
                    if ($result === false) {
                        $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.fail')) . $vt->getErrs()[0] . "<br>";  // 多个规则提示最前面一条
                    } elseif ($warn) {
                        $text .= $warn;
                    } elseif (!in_array($field['unit'], $unitOption)) {
                        $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.unitNotIn')) . "<br>";
                    } else {
                        $field['bomVersion'] = $field['bomVersion'] ?: $this->getBomVersion($field['materialId']);
                        if (empty($cell['BOM编号'])) {
                            $bom = query(self::table, "materialId = '$material[id]' and bomVersion = '$cell[BOM版本]' and coid = '" . self::$coid . "'");
                        } else {
                            $bom = query(self::table, "orderNo = '$cell[BOM编号]' and coid = '" . self::$coid . "'");
                        }
                        if (!$bom['id']) {
                            // 不存在
                            $userNo = codeTemplateClass::generateCode(self::page, [
                                'prefix' => 'BOM' . date('Ymd'),
                                'table'  => self::table,
                                'field'  => 'orderNo',
                                'where'  => " and coid = '" . self::$coid . "'",
                            ], $field);
                            $field  = array_merge($field, [
                                'id'      => self::getId(),
                                'coid'    => self::$coid,
                                'orderNo' => $cell['BOM编号'] ?: $userNo,
                                'state'   => '启用',
                                'stid'    => $this->control['stid'],
                            ]);
                            $bom    = $field;
                            $warn   = static::insert([
                                "table" => "bom",
                                "field" => $field
                            ]);
                        } else {
                            // 已存在此bom表
                            $warn = static::update([
                                "table" => "bom",
                                "field" => $field,
                                'where' => " id = '{$bom['id']}' ",
                            ]);
                        }
                        // 插入子表
                        if (!in_array($warn, ['新增成功', '更新成功'])) {
                            $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.parentFail')) . "<br>";
                        } else {
                            if (static::total(array('table' => self::table, "where" => "materialId = '$field[materialId]' and coid = '" . self::$coid . "' and isDefault = 1")) == 0) {
                                update(array('table' => self::table, 'field' => array('isDefault' => 1), 'where' => "id ='$bom[id]'"));
                            }
                            if ($field['isDefault'] == 1) {
                                update(array('table' => self::table, 'field' => array('isDefault' => 0), 'where' => "materialId = '$field[materialId]' and id !='$bom[id]'"));
                            }

                            /*********导入子件******************/
                            $childField    = [
                                'typeId' => $cell['子件分类'],
                                'code'   => $cell['子物料编码'],
                                'name'   => $cell['子物料名称'],
                                'model'  => $cell['子物料规格型号'],
                                'source' => $cell['子物料来源'] ?: '采购',
                                'unit'   => $cell['子物料单位'],
                            ];
                            $materialChild = $this->createMaterial($childField);
                            $childBom      = query(self::table, "materialId = '$materialChild[id]' and bomVersion =  '$cell[子物料BOM版本]' and coid = '" . self::$coid . "'");
                            $mxField       = [
                                'num'        => $cell['额定数量'] ? self::formattingFigure($cell['额定数量'], 'numPrecision') : '',
                                'unit'       => $childField['unit'] ?: $materialChild['unit'],
                                'materialId' => $materialChild['id'],
                                'bomId'      => $childBom['id'],
                                'loss'       => (float)$cell['损耗率'] / 100,
                                'pickType'   => $cell['供料方式'] ?: '领料'
                            ];

                            $annotation = [
                                'unit'       => lang('bom.importData.childUnit'),
                                'num'        => lang('bom.importData.numMx'),
                                'materialId' => lang('bom.importData.child'),
                            ];
                            $rules      = [
                                'unit'       => 'required',
                                'num'        => 'required',
                                'materialId' => 'required',
                            ];
                            $unitOption = machiningOrderClass::unitOption($materialChild['id']);

                            if ($mxField['pickType'] == '发料') {
                                $warehouse              = query('warehouse', "orderNo = '$cell[发料仓编码]' and coid = '" . self::$coid . "'");
                                $mxField['warehouseId'] = $warehouse['id'];
                            }

                            // 校验是否符合规则
                            $result = $vt->setAliases($annotation)->validate($mxField, $rules)->isOk();
                            if ($result === false) {
                                $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.fail')) . $vt->getErrs()[0] . "<br>";  // 多个规则提示最前面一条
                            } elseif (!in_array($mxField['unit'], $unitOption)) {
                                $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.childUnitNotIn')) . "<br>";
                            } elseif (!in_array($mxField['pickType'], $this->pickOption)) {
                                $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.pickTypeNotIn')) . "<br>";
                            } elseif ($mxField['pickType'] == '发料' && !empty($cell['发料仓编码']) && empty($mxField['warehouseId'])) {
                                $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.notFindWareHouse')) . "<br>";
                            } else {
                                $flag = true;
                                //判断相互的组成关系，防止死循环
                                if ($this->isRepeatParent($materialChild['id'], $bom['materialId'], $mxField['bomId'])) {
                                    $text .= str_replace(['{{i}}', '{{materialName}}'], [$row_list, $materialChild['name']], lang('bom.importData.parentLog')) . "<br>";
                                    $flag = false;
                                }
                                if ($flag) {
                                    $bomMx = query(self::tableMx, "orderId = '$bom[id]' and coid = '" . self::$coid . "' and materialId = '$materialChild[id]'");
                                    if (!$bomMx['id']) {
                                        // 不存在
                                        $mxField = array_merge($mxField, [
                                            'id'      => self::getId(),
                                            'orderId' => $bom['id'],
                                            'coid'    => self::$coid,
                                        ]);
                                        $warn    = static::insert([
                                            "table" => self::tableMx,
                                            "field" => $mxField
                                        ]);
                                        $bomMx   = $mxField;
                                    } else {
                                        // 已存在此bom表 新增 子表
                                        $warn = static::update([
                                            "table" => self::tableMx,
                                            "field" => $mxField,
                                            'where' => " id = '{$bomMx['id']}' ",
                                        ]);
                                    }
                                    // 插入子表
                                    if (!in_array($warn, ['新增成功', '更新成功'])) {
                                        $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.childFail')) . "<br>";
                                    } else {
                                        $x++;
                                        $text .= str_replace(['{{i}}'], [$row_list], lang('bom.importData.success')) . "<br>";
                                    }
                                    if ($cell['子物料BOM版本'])
                                        $bomRelative[$bomMx['id']] = ['bomVersion' => $cell['子物料BOM版本'], 'materialId' => $materialChild['id']];
                                }
                            }
                        }
                    }
                }
            }
            //关联子物料的BOM下一级
            if (isset($bomRelative)) {
                foreach ($bomRelative as $bomMxId => $array) {
                    $childBom      = query(self::table, "materialId = '$array[materialId]' and bomVersion =  '$array[bomVersion]' and coid = '" . self::$coid . "'");
                    self::update(['table' => self::tableMx, 'field' => ['bomId' => $childBom['id']], 'where' => "id = '$bomMxId'"]);
                }
            }
            materialClass::getSidebarData(reset: true); //重置左侧分类导航栏

            $total        = count($data) - 1;
            $json['data'] = [
                'text'  => $text,
                'title' => "您导入了{$total}条数据，成功{$x}条，失败" . ($total - $x) . "条",
            ];
            $this->logText(["type" => self::page, "text" => $text]);
            $json['warn'] = 2;
        }
        return json_encode($json, 320);
    }

    /**
     * 导出
     */
    public function exportData()
    {
        $templateId     = $this->get('templateId');
        $checkedId      = $this->get('checkedId') ? explode(',', $this->get('checkedId')) : [];
        if (!$this->power(self::page, 'export')) {
            $_SESSION['warn'] = lang('bom.exportData.power');
        } else {
            $data = [];
            /***********标题**********/
            $title        = [];
            $tempFieldAll = importTemplateClass::templateField(self::page, 'exportFieldInit', id:$templateId);
            foreach ($tempFieldAll as $array) {
                if ($array['display']) {
                    $title[] = $array['aliasName'];
                }
            }
            //判断是否选中导出
            if (!self::is_null_array($checkedId)) {
                $result = find(array("table" => self::table . " as a join material as b on a.materialId = b.id", 'field' => "a.*,b.name,b.model,b.code,b.typeId", "where" => "a.id in ('" . implode("','", $checkedId) . "') order by a.time desc"))['array'];
            } else {
                $sql    = $_SESSION[self::page]['sql'];
                $result = sqlFind($sql);
            }
            //导出数据生成
            foreach ($result as $array) {
                $column         = [];
                $materialParent = query('material', "id = '$array[materialId]'");
                $bomMx          = find(array('table' => self::tableMx, "where" => "orderId = '$array[id]' order by list asc"));
                foreach ($bomMx['array'] as $index => $val) {
                    foreach ($tempFieldAll as $templateField) {
                        if ($templateField['display']) {
                            $material = query('material', "id = '$val[materialId]'");
                            $bom      = query(self::table, "id = '$val[bomId]'");
                            if ($index > 0) {
                                $array['orderNo'] = '';
                                $array['bomVersion'] = '';
                                $array['description'] = '';
                                $array['bomType'] = '';
                                $materialParent['code'] = '';
                                $materialParent['name'] = '';
                                $array['unit'] = '';
                                $array['num'] = '';
                                $array['text'] = '';
                            }
                            $warehouse = query('warehouse', "id = '$val[warehouseId]'");
                            $column[]  = match ($templateField['columnName']) {
                                'BOM编号' => $array['orderNo'],
                                'BOM版本' => $array['bomVersion'],
                                'BOM描述' => $array['description'],
                                'BOM用途' => $array['bomType'],
                                '父件编码' => $materialParent['code'],
                                '父件名称' => $materialParent['name'],
                                '单位' => $array['unit'],
                                '基准数量' => $array['num'],
                                '备注' => $array['text'],
                                '子物料编码' => $material['code'],
                                '子物料名称' => $material['name'],
                                '子物料单位' => $val['unit'],
                                '子物料BOM编号' => $bom['orderNo'],
                                '子物料BOM版本' => $bom['bomVersion'],
                                '额定数量' => self::lostZero($val['num'], 'numPrecision'),
                                '损耗率' => $val['loss'] * 100,
                                '供料方式' => $val['pickType'],
                                '发料仓库' => $warehouse['name'],
                                default => '',
                            };
                        }
                    }
                    $data[] = $column;
                }
            }
            $text = str_replace(['{{staffName}}'], [$this->control['name']], lang('bom.exportData.log'));
            $this->logText(["type" => self::page, "text" => $text]);
            $this->excelOut($title, $data, lang('bom.exportData.fileName') . '.xlsx');
            exit(0);
        }
        header("Location:" . getenv("HTTP_REFERER"));
    }


    /**
     * 导入模板字段初始化
     * @return array[]
     */
    public function importFieldInit($classify = ''): array
    {
        return match ($classify) {
            default => [
                [
                    'columnName' => 'BOM编号',
                    'isMust'     => false,
                ],
                [
                    'columnName' => 'BOM版本',
                    'isMust' => true,
                ],
                [
                    'columnName' => 'BOM描述',
                    'isMust' => true,
                ],
                [
                    'columnName' => 'BOM用途',
                    'isMust' => true,
                ],
                [
                    'columnName' => '父件分类',
                    'isMust' => false,
                ],
                [
                    'columnName' => '父件编码',
                    'isMust' => true,
                ],
                [
                    'columnName' => '父件名称',
                    'isMust' => false,
                ],
                [
                    'columnName' => '规格型号',
                    'isMust' => false,
                ],
                [
                    'columnName' => '来源',
                    'isMust' => false,
                ],
                [
                    'columnName' => '单位',
                    'isMust' => false,
                ],
                [
                    'columnName' => '基准数量',
                    'isMust' => false,
                ],
                [
                    'columnName' => '是否默认',
                    'aliasName'  => '是否默认(是/否)',
                    'isMust' => false,
                ],
                [
                    'columnName' => '备注',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子件分类',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子物料编码',
                    'isMust' => true,
                ],
                [
                    'columnName' => '子物料名称',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子物料规格型号',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子物料来源',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子物料单位',
                    'isMust' => false,
                ],
                [
                    'columnName' => '子物料BOM版本',
                    'isMust' => false,
                ],
                [
                    'columnName' => '额定数量',
                    'isMust' => true,
                ],
                [
                    'columnName' => '损耗率',
                    'isMust' => false,
                ],
                [
                    'columnName' => '供料方式',
                    'isMust' => false,
                ],
                [
                    'columnName' => '发料仓编码',
                    'isMust' => false,
                ],
                [
                    'columnName' => '发料仓名称',
                    'isMust' => false,
                ],
            ]
        };
    }

    /**
     * 导出模板字段初始化
     * @return array[]
     */
    public function exportFieldInit($classify = ''): array
    {
        return match ($classify) {
            default => [
                [
                    'columnName' => 'BOM编号',
                ],
                [
                    'columnName' => 'BOM版本',
                ],
                [
                    'columnName' => 'BOM描述',
                ],
                [
                    'columnName' => 'BOM用途',
                ],
                [
                    'columnName' => '父件编码',
                ],
                [
                    'columnName' => '父件名称',
                ],
                [
                    'columnName' => '单位',
                ],
                [
                    'columnName' => '基准数量',
                ],
                [
                    'columnName' => '备注',
                ],
                [
                    'columnName' => '子物料编码',
                ],
                [
                    'columnName' => '子物料名称',
                ],
                [
                    'columnName' => '子物料单位',
                ],
                [
                    'columnName' => '子物料BOM版本',
                ],
                [
                    'columnName' => '子物料BOM版本',
                ],
                [
                    'columnName' => '额定数量',
                ],
                [
                    'columnName' => '损耗率',
                    'aliasName'  => '损耗率%',
                ],
                [
                    'columnName' => '供料方式',
                ],
                [
                    'columnName' => '发料仓库',
                ],
            ]
        };
    }
}
